package cc.verywell.pureblock.util;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.StandardSocketOptions;
import java.net.UnknownHostException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.concurrent.TimeUnit;

import cc.verywell.pureblock.log.Pblog;
import cc.verywell.pureblock.net.AioProvider;

/**
* 
* Copyright 2019 TanYaqiu
* @author TanYaqiu 
* @address flat 601
* @date 2019年3月16日 下午4:25:18
*/
public class StringUtil{
	
	static public int compare(String o1, String o2) {
		if(o1==o2)return 0;
		if(o1==null)return -1;
		if(o2==null)return 1;
		byte[] b1 = stringToByte(o1);
		byte[] b2 = stringToByte(o2);
		int len = b1.length<b2.length?b1.length:b2.length;
		for (int i = 0; i < len; i++) {
			if(b1[i]!=b2[i]) {
				return b1[i]&0xFF-b2[i]&0xFF;
			}
		}
		return b1.length-b2.length;
	}
	

	////序列化BigEndian - 20190316tyq腹痛日;
	/**
	 * Copyright 2019 TanYaqiu
	 * @author TanYaqiu 
	 * @address flat 601
	 */
	public static int readLength(int lengthSize,final ByteBuffer bb) {
		if(lengthSize==0)return bb.remaining();
		int size = 0;
		while(0<lengthSize--) {
			size <<= 8;
			size |= (0xFF & bb.get());
		}
		return size;
	}
	/**
	 * Copyright 2019 TanYaqiu
	 * @author TanYaqiu 
	 * @address flat 601
	 */
	public static void writeLength(int lengthSize,final int length,final ByteBuffer bb) {
		if(lengthSize<=0)throw new NullPointerException();
		if((length >>> (8*lengthSize))!=0)throw new IllegalArgumentException("length "+Integer.toHexString(length)+" is too big cannot put in size "+lengthSize);
		while(0<lengthSize--) {
		     bb.put((byte)((length >>> (8*lengthSize)) & 0xFF));
		}
	}
	/**
	 * Copyright 2019 TanYaqiu
	 * @author TanYaqiu 
	 * @address flat 601
	 */
	public static byte[] getLength(int lengthSize,final int length) {
		if(lengthSize<=0)throw new NullPointerException();
		if((length >>> (8*lengthSize))!=0)throw new IllegalArgumentException("length "+Integer.toHexString(length)+" is too big cannot put in size "+lengthSize);
		byte[] bb = new byte[lengthSize];
		lengthSize = 0;
		while(lengthSize<bb.length) {
		     bb[lengthSize]=(byte)((length >>> (8*lengthSize)) & 0xFF);
		     lengthSize++;
		}
		return bb;
	}

	////20190316tyq腹痛日
	static public Charset CHARSET;
	static{
		String charsetName = "UTF-8";
		try {
			CHARSET = Charset.forName(charsetName);
		} catch (Throwable e) {
			if(Pblog.INIT)Pblog.INIT("Charset "+charsetName+" cannot init: ",e);
			throw e;
		}
	}
	static public String byteToString(byte[] bs) {
		return new String(bs,CHARSET);
	}
	static public String byteToString(byte[] bs, int offset, int length) {
		return new String(bs, offset, length,CHARSET);
	}
	static public byte[] stringToByte(String str) {
		return str.getBytes(CHARSET);
	}
	/**
	 * 
	 * Copyright 2019 TanYaqiu
	 * @author TanYaqiu 
	 * @address flat 601
	 */
	static public void stringToByteBuffer(final int lengthSize,final String fromString,final ByteBuffer toBuffer) {
		ByteBuffer encoded = CHARSET.encode(fromString);
		writeLength(lengthSize, encoded.remaining(), toBuffer);
		toBuffer.put(encoded);
	}
	
	/**
	 * 
	 * Copyright 2019 TanYaqiu
	 * @author TanYaqiu 
	 * @address flat 601
	 */
	static public String byteBufferToString(final int lengthSize,final ByteBuffer fromBuffer) {
//		System.out.print(position);
//		System.out.print(',');
		int position = readLength(lengthSize,fromBuffer);
		position += fromBuffer.position();
//		System.out.print(position);
//		System.out.print(',');
		int limit = fromBuffer.limit();
		if(position>limit)throw new BufferUnderflowException();
		if(position<limit) {
			fromBuffer.limit(position);
			try {
//				System.out.print(fromBuffer.remaining());
				String str = CHARSET.decode(fromBuffer).toString();
//				System.out.print(',');
//				System.out.print(position);
//				System.out.print(',');
//				System.out.println(str);
				return str;
			}finally {
				fromBuffer.limit(limit).position(position);
			}
		}else{
			return CHARSET.decode(fromBuffer).toString();
		}
	}
	
	
	/////////////////////地址相关
	/**
	 * InetAddress localHost = InetAddress.getLocalHost();<br>
	 * InetAddress hostName = InetAddress.getByName("your host name");<br>
	 * InetAddress ipAddress = InetAddress.getByName("your ip address");<br>
	 * 大家都试试看那个执行最快？我机是localHost最快，ipAddress最慢.
	 * @param port 端口
	 * @return
	 * @throws UnknownHostException
	 */
	static public String portToString(int port) throws UnknownHostException{
		InetAddress a = InetAddress.getLocalHost();
		InetSocketAddress b = new InetSocketAddress(a,port);
		return portToString(b);
	}
	static public String portToString(InetSocketAddress a) {
		return a.getHostString()+':'+a.getPort();
	}
	static public String[] localPortToString(InetSocketAddress sa, AsynchronousChannelGroup acg) {
		InetAddress h = sa.getAddress();
		if(!h.isAnyLocalAddress())return new String[]{portToString(sa)};
		ArrayList<String> al = new ArrayList<>();
		
		try {
			Enumeration<NetworkInterface> ns = NetworkInterface.getNetworkInterfaces();
		    while (ns.hasMoreElements()) {
			      NetworkInterface n = ns.nextElement();
			      if (!n.isUp() || n.isLoopback() || n.isVirtual()) continue;
			      Enumeration<InetAddress> as = n.getInetAddresses();
			      while (as.hasMoreElements()) {
			        InetAddress a = as.nextElement();
			        if(a.isAnyLocalAddress() || a.isLoopbackAddress()) continue;
			        /**重点来了*/
			        sa = new InetSocketAddress(a,sa.getPort());
			        AsynchronousSocketChannel ch = null;
					try {
						ch = AsynchronousSocketChannel.open(acg);
						ch.setOption(StandardSocketOptions.SO_REUSEADDR, true);
						ch.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
						ch.connect(sa).get(AioProvider.TIME_OUT, TimeUnit.SECONDS);
				        al.add(portToString(sa));
				        if(Pblog.IO)Pblog.IO("local addr ",sa," reachable.");
					}catch(Throwable e) {
						//if(Pblog.IO)Pblog.printIO("local addr ",sa," cannot reach. ",e.getMessage());
					}finally {
						try {
							if(ch!=null)ch.close();
						} catch (IOException e1) {
							if(Pblog.IO)Pblog.IO(e1);
						}
					}
			      }
			    }
		} catch (SocketException e) {
			if(Pblog.IO)Pblog.IO(e);
		}

		return al.toArray(new String[al.size()]);
	}
	static public InetSocketAddress stringToPort(String str) throws IllegalArgumentException {
		int i = str.lastIndexOf(':');
		if(i<=0)throw new IllegalArgumentException(str+" cannot find port");
		String host = str.substring(0, i);
		int port = Integer.valueOf(str.substring(i+1));
		return new InetSocketAddress(host, port);
	}
	
	

}
